/*
 * main.c
 * 
 * Copyright(c) 2021 Cai_XL <Cai_XL@outlook.com>
 * bilibili : https://space.bilibili.com/54910927
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * default CCU settings:
 * CPU clock source:	OSC24M = 24MHz
 * AHB clock source:	OSC24M = 24MHz
 * AHB clock freq:		AHB_CLK_SRC / 2 = 12MHz 
 * APB clock freq:		AHB_CLK / 2 = 6MHz
 * 
 * after initialization:
 * CPU clock source:	PLL_CPU = 408MHz
 * AHB clock source:	PLL_PERIPH / AHB_PRE_DIV = 600 / 3 = 200MHz
 * AHB clock freq:		AHB_CLK_SRC / AHB_CLK_DIV_RATIO = 200 / 1 = 200MHz
 * APB clock freq:		AHB_CLK / APB_CLK_DIV_RATIO = 200 / 2 = 100MHz
*/

#include "main.h"

//#define CCU_CPU_INIT_ENABLE	// enable initialize CPU clock source,AHB/APB clock source


static void delay(void);

int main(void)
{
	#ifdef CCU_CPU_INIT_ENABLE 				// enable initialize AHB/APB clock source

	uint32_t timeout;						// variable to wait PLL stable

	CCU->AHB_APB_HCLKC_CFG_REG &= ~(3<<8);	// APB_CLK_DIV_RATIO = 2	
	// AHB_APB_HCLKC_CFG_REG[9:8] : APB_CLK_DIV_RATIO
	// 0x : 2 (defaut)
	// 10 : 4
	// 11 : 8

	CCU->AHB_APB_HCLKC_CFG_REG &= ~(3<<4);	// AHB_CLK_DIV_RATIO = 1
	// AHB_APB_HCLKC_CFG_REG[5:4] : AHB_CLK_DIV_RATIO
	// 00 : 1
	// 01 : 2 (default)
	// 10 : 4
	// 11 : 8

	CCU->AHB_APB_HCLKC_CFG_REG |= (2<<6);	//AHB_PRE_DIV = 3
	// AHB_APB_HCLKC_CFG_REG[7:6] : AHB_PRE_DIV
	// 00 : 1 (default)
	// 01 : 2
	// 10 : 3
	// 11 : 4

	/* enable PLL_PERIPH */
	CCU->PLL_GLOBAL_TIME_REG = 0x1ff;		// PLL lock time
	CCU->PLL_PERIPH_CTRL_REG |= (1<<31);	// enable PLL_PERIPH in 600MHz(default)
	timeout = 0xfff;
	while((timeout--) && !(CCU->PLL_PERIPH_CTRL_REG & (1<<28)));	// wait PLL_PERIPH stable

	CCU->AHB_APB_HCLKC_CFG_REG |= (3<<12);	// AHB_CLK_SRC = PLL_PERIPH / AHB_PRE_DIV
	// AHB_APB_HCLKC_CFG_REG[13:12] : AHB_CLK_SRC_SEL
	// 00 : LOSC
	// 01 : OSC24M (default)
	// 10 : CPUCLK
	// 11 : PLL_PERIPH / AHB_PRE_DIV

	CCU->PLL_CPU_TIME_REG = 0x1ff;			// PLL lock time
	CCU->PLL_CPU_CTRL_REG |= (1<<31);		// enable PLL_CPU in 408MHz(default)
	timeout = 0xfff;
	while((timeout--) && !(CCU->PLL_CPU_CTRL_REG & (1<<28)));	// wait PLL_CPU stable

	CCU->CPU_CLK_SRC_REG |= (1<<17);		// CPUCLK = PLL_CPU
	// CPU_CLK_SRC_REG[18:17] : CPU_CLK_SRC_SEL
	// 00 : LOSC
	// 01 : OSC24M (default)
	// 1x : PLL_CPU

	delay();								// wait all clock signal stable
	
	#endif /** CCU_CPU_INIT_ENABLE **/

	GPIOE_Init();							// initialize GPIOE

	while(1)
	{
		GPIOE_SetPins(0x0f);				// output high
		delay();							// wait a monent
		GPIOE_ResetPins(0x0f);				// output low
		delay();							// wait a monent
	}
}

static void delay(void)		// about 408ms when CPU_CLK_SRC uses OSC24M
{
	__asm volatile(
	" ldr r0, =76480	\n" 
	" loop:cmp r0,#0	\n"
	" beq exit 			\n"
	" sub r0,r0,#1 		\n"
	" b loop 			\n"
	"exit:nop 			\n"
	);
}